package com.project.common.data.mybatis.provider.dm;

import com.project.common.data.mybatis.metadata.TableColumn;
import com.project.common.data.mybatis.metadata.TableMetadata;
import com.project.common.data.mybatis.provider.CRUDProvider;
import com.project.common.data.mybatis.provider.utils.ProviderUtils;
import com.project.constants.Constants;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.jdbc.SQL;

import java.util.function.Predicate;
import java.util.stream.Stream;

public class DmCRUDProvider implements CRUDProvider {


    /**
     * 生成 Insert 语句
     */
    @Override
    public String insert(ProviderContext context) {
        Class<?> clazz = this.getPersistenceType(context);
        TableMetadata tableMetadata = TableMetadata.forClass(clazz);
        String insertInto = "\"" + Constants.SCHEMA_NAME + "\"." + "\"" +
                tableMetadata.getTableName() + "\"";
        String primaryKey = tableMetadata.getKeyColumn().getName();
        String[] insertColumn = Stream.of(tableMetadata.getColumns())
                .filter(a -> !primaryKey.equals(a.getName()))
                .map(a -> "\"" + a.getName() + "\"").toArray(String[]::new);
        String[] insertValue = Stream.of(tableMetadata.getColumns())
                .filter(a -> !primaryKey.equals(a.getName()))
                .map(ProviderUtils::buildParameter)
                .toArray(String[]::new);
        return new SQL().INSERT_INTO(insertInto)
                .INTO_COLUMNS(insertColumn).INTO_VALUES(insertValue).toString();
    }

    /**
     * 生成 Update 语句
     */
    @Override
    public String update(ProviderContext context) {
        return this.doUpdate(null, context, false);
    }

    /**
     * 根据持久化对象生成 Update 语句
     */
    @Override
    public String updateSelective(Object entity, ProviderContext context) {
        return this.doUpdate(entity, context, true);
    }

    @Override
    public String doUpdate(Object entity, ProviderContext context, boolean selective) {
        Class<?> clazz = getPersistenceType(context);
        TableMetadata tableMetadata = TableMetadata.forClass(clazz);
        String updateInto = "\"" + Constants.SCHEMA_NAME + "\"." + "\"" +
                tableMetadata.getTableName() + "\"";
        Predicate<TableColumn> predicate = !selective ?
                (tableColumn -> !tableColumn.isKey()) :
                (tableColumn -> !tableColumn.isKey() && ProviderUtils.checkField(tableColumn, clazz, entity));
        String[] sets = Stream.of(tableMetadata.getColumns())
                .filter(predicate)
                .map(ProviderUtils::buildDmAssignment)
                .toArray(String[]::new);
        return new SQL().UPDATE(updateInto).SET(sets)
                .WHERE(ProviderUtils.buildDmAssignment(tableMetadata.getKeyColumn())).toString();
    }

    @Override
    public String get(ProviderContext context) {
        Class<?> clazz = this.getPersistenceType(context);
        TableMetadata tableMetadata = TableMetadata.forClass(clazz);
        String getFrom = "\"" + Constants.SCHEMA_NAME + "\"." + "\"" +
                tableMetadata.getTableName() + "\"";
        return new SQL()
                .SELECT(Stream.of(tableMetadata.getColumns())
                        .map(a -> "\"" + a.getName() + "\"")
                        .toArray(String[]::new))
                .FROM(getFrom)
                .WHERE(ProviderUtils.buildDmAssignment(tableMetadata.getKeyColumn()))
                .toString();
    }
}
